home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / generic / tk3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  26.0 KB  |  785 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tk3d.c --
  3.  *
  4.  *    This module provides procedures to draw borders in
  5.  *    the three-dimensional Motif style.
  6.  *
  7.  * Copyright (c) 1990-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tk3d.c 1.60 97/01/13 17:23:10
  14.  */
  15.  
  16. #include <tk3d.h>
  17.  
  18. /*
  19.  * Hash table to map from a border's values (color, etc.) to a
  20.  * Border structure for those values.
  21.  */
  22.  
  23. static Tcl_HashTable borderTable;
  24. typedef struct {
  25.     Tk_Uid colorName;        /* Color for border. */
  26.     Colormap colormap;        /* Colormap used for allocating border
  27.                  * colors. */
  28.     Screen *screen;        /* Screen on which border will be drawn. */
  29. } BorderKey;
  30.  
  31. static int initialized = 0;    /* 0 means static structures haven't
  32.                  * been initialized yet. */
  33.  
  34. /*
  35.  * Forward declarations for procedures defined in this file:
  36.  */
  37.  
  38. static void        BorderInit _ANSI_ARGS_((void));
  39. static int        Intersect _ANSI_ARGS_((XPoint *a1Ptr, XPoint *a2Ptr,
  40.                 XPoint *b1Ptr, XPoint *b2Ptr, XPoint *iPtr));
  41. static void        ShiftLine _ANSI_ARGS_((XPoint *p1Ptr, XPoint *p2Ptr,
  42.                 int distance, XPoint *p3Ptr));
  43.  
  44. /*
  45.  *--------------------------------------------------------------
  46.  *
  47.  * Tk_Get3DBorder --
  48.  *
  49.  *    Create a data structure for displaying a 3-D border.
  50.  *
  51.  * Results:
  52.  *    The return value is a token for a data structure
  53.  *    describing a 3-D border.  This token may be passed
  54.  *    to Tk_Draw3DRectangle and Tk_Free3DBorder.  If an
  55.  *    error prevented the border from being created then
  56.  *    NULL is returned and an error message will be left
  57.  *    in interp->result.
  58.  *
  59.  * Side effects:
  60.  *    Data structures, graphics contexts, etc. are allocated.
  61.  *    It is the caller's responsibility to eventually call
  62.  *    Tk_Free3DBorder to release the resources.
  63.  *
  64.  *--------------------------------------------------------------
  65.  */
  66.  
  67. Tk_3DBorder
  68. Tk_Get3DBorder(interp, tkwin, colorName)
  69.     Tcl_Interp *interp;        /* Place to store an error message. */
  70.     Tk_Window tkwin;        /* Token for window in which border will
  71.                  * be drawn. */
  72.     Tk_Uid colorName;        /* String giving name of color
  73.                  * for window background. */
  74. {
  75.     BorderKey key;
  76.     Tcl_HashEntry *hashPtr;
  77.     register TkBorder *borderPtr;
  78.     int new;
  79.     XGCValues gcValues;
  80.  
  81.     if (!initialized) {
  82.     BorderInit();
  83.     }
  84.  
  85.     /*
  86.      * First, check to see if there's already a border that will work
  87.      * for this request.
  88.      */
  89.  
  90.     key.colorName = colorName;
  91.     key.colormap = Tk_Colormap(tkwin);
  92.     key.screen = Tk_Screen(tkwin);
  93.  
  94.     hashPtr = Tcl_CreateHashEntry(&borderTable, (char *) &key, &new);
  95.     if (!new) {
  96.     borderPtr = (TkBorder *) Tcl_GetHashValue(hashPtr);
  97.     borderPtr->refCount++;
  98.     } else {
  99.     XColor *bgColorPtr;
  100.  
  101.     /*
  102.      * No satisfactory border exists yet.  Initialize a new one.
  103.      */
  104.     
  105.     bgColorPtr = Tk_GetColor(interp, tkwin, colorName);
  106.     if (bgColorPtr == NULL) {
  107.         Tcl_DeleteHashEntry(hashPtr);
  108.         return NULL;
  109.     }
  110.  
  111.     borderPtr = TkpGetBorder();
  112.     borderPtr->screen = Tk_Screen(tkwin);
  113.     borderPtr->visual = Tk_Visual(tkwin);
  114.     borderPtr->depth = Tk_Depth(tkwin);
  115.     borderPtr->colormap = key.colormap;
  116.     borderPtr->refCount = 1;
  117.     borderPtr->bgColorPtr = bgColorPtr;
  118.     borderPtr->darkColorPtr = NULL;
  119.     borderPtr->lightColorPtr = NULL;
  120.     borderPtr->shadow = None;
  121.     borderPtr->bgGC = None;
  122.     borderPtr->darkGC = None;
  123.     borderPtr->lightGC = None;
  124.     borderPtr->hashPtr = hashPtr;
  125.     Tcl_SetHashValue(hashPtr, borderPtr);
  126.     
  127.     /*
  128.      * Create the information for displaying the background color,
  129.      * but delay the allocation of shadows until they are actually
  130.      * needed for drawing.
  131.      */
  132.     
  133.     gcValues.foreground = borderPtr->bgColorPtr->pixel;
  134.     borderPtr->bgGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  135.     }
  136.     return (Tk_3DBorder) borderPtr;
  137. }
  138.  
  139. /*
  140.  *--------------------------------------------------------------
  141.  *
  142.  * Tk_Draw3DRectangle --
  143.  *
  144.  *    Draw a 3-D border at a given place in a given window.
  145.  *
  146.  * Results:
  147.  *    None.
  148.  *
  149.  * Side effects:
  150.  *    A 3-D border will be drawn in the indicated drawable.
  151.  *    The outside edges of the border will be determined by x,
  152.  *    y, width, and height.  The inside edges of the border
  153.  *    will be determined by the borderWidth argument.
  154.  *
  155.  *--------------------------------------------------------------
  156.  */
  157.  
  158. void
  159. Tk_Draw3DRectangle(tkwin, drawable, border, x, y, width, height,
  160.     borderWidth, relief)
  161.     Tk_Window tkwin;        /* Window for which border was allocated. */
  162.     Drawable drawable;        /* X window or pixmap in which to draw. */
  163.     Tk_3DBorder border;        /* Token for border to draw. */
  164.     int x, y, width, height;    /* Outside area of region in
  165.                  * which border will be drawn. */
  166.     int borderWidth;        /* Desired width for border, in
  167.                  * pixels. */
  168.     int relief;            /* Type of relief: TK_RELIEF_RAISED,
  169.                  * TK_RELIEF_SUNKEN, TK_RELIEF_GROOVE, etc. */
  170. {
  171.     if (width < 2*borderWidth) {
  172.     borderWidth = width/2;
  173.     }
  174.     if (height < 2*borderWidth) {
  175.     borderWidth = height/2;
  176.     }
  177.     Tk_3DVerticalBevel(tkwin, drawable, border, x, y, borderWidth, height,
  178.         1, relief);
  179.     Tk_3DVerticalBevel(tkwin, drawable, border, x+width-borderWidth, y,
  180.         borderWidth, height, 0, relief);
  181.     Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, borderWidth,
  182.         1, 1, 1, relief);
  183.     Tk_3DHorizontalBevel(tkwin, drawable, border, x, y+height-borderWidth,
  184.         width, borderWidth, 0, 0, 0, relief);
  185. }
  186.  
  187. /*
  188.  *--------------------------------------------------------------
  189.  *
  190.  * Tk_NameOf3DBorder --
  191.  *
  192.  *    Given a border, return a textual string identifying the
  193.  *    border's color.
  194.  *
  195.  * Results:
  196.  *    The return value is the string that was used to create
  197.  *    the border.
  198.  *
  199.  * Side effects:
  200.  *    None.
  201.  *
  202.  *--------------------------------------------------------------
  203.  */
  204.  
  205. char *
  206. Tk_NameOf3DBorder(border)
  207.     Tk_3DBorder border;        /* Token for border. */
  208. {
  209.     TkBorder *borderPtr = (TkBorder *) border;
  210.  
  211.     return ((BorderKey *) borderPtr->hashPtr->key.words)->colorName;
  212. }
  213.  
  214. /*
  215.  *--------------------------------------------------------------------
  216.  *
  217.  * Tk_3DBorderColor --
  218.  *
  219.  *    Given a 3D border, return the X color used for the "flat"
  220.  *    surfaces.
  221.  *
  222.  * Results:
  223.  *    Returns the color used drawing flat surfaces with the border.
  224.  *
  225.  * Side effects:
  226.  *    None.
  227.  *
  228.  *--------------------------------------------------------------------
  229.  */
  230. XColor *
  231. Tk_3DBorderColor(border)
  232.     Tk_3DBorder border;        /* Border whose color is wanted. */
  233. {
  234.     return(((TkBorder *) border)->bgColorPtr);
  235. }
  236.  
  237. /*
  238.  *--------------------------------------------------------------------
  239.  *
  240.  * Tk_3DBorderGC --
  241.  *
  242.  *    Given a 3D border, returns one of the graphics contexts used to
  243.  *    draw the border.
  244.  *
  245.  * Results:
  246.  *    Returns the graphics context given by the "which" argument.
  247.  *
  248.  * Side effects:
  249.  *    None.
  250.  *
  251.  *--------------------------------------------------------------------
  252.  */
  253. GC
  254. Tk_3DBorderGC(tkwin, border, which)
  255.     Tk_Window tkwin;        /* Window for which border was allocated. */
  256.     Tk_3DBorder border;        /* Border whose GC is wanted. */
  257.     int which;            /* Selects one of the border's 3 GC's:
  258.                  * TK_3D_FLAT_GC, TK_3D_LIGHT_GC, or
  259.                  * TK_3D_DARK_GC. */
  260. {
  261.     TkBorder * borderPtr = (TkBorder *) border;
  262.  
  263.     if ((borderPtr->lightGC == None) && (which != TK_3D_FLAT_GC)) {
  264.     TkpGetShadows(borderPtr, tkwin);
  265.     }
  266.     if (which == TK_3D_FLAT_GC) {
  267.     return borderPtr->bgGC;
  268.     } else if (which == TK_3D_LIGHT_GC) {
  269.     return borderPtr->lightGC;
  270.     } else if (which == TK_3D_DARK_GC){
  271.     return borderPtr->darkGC;
  272.     }
  273.     panic("bogus \"which\" value in Tk_3DBorderGC");
  274.  
  275.     /*
  276.      * The code below will never be executed, but it's needed to
  277.      * keep compilers happy.
  278.      */
  279.  
  280.     return (GC) None;
  281. }
  282.  
  283. /*
  284.  *--------------------------------------------------------------
  285.  *
  286.  * Tk_Free3DBorder --
  287.  *
  288.  *    This procedure is called when a 3D border is no longer
  289.  *    needed.  It frees the resources associated with the
  290.  *    border.  After this call, the caller should never again
  291.  *    use the "border" token.
  292.  *
  293.  * Results:
  294.  *    None.
  295.  *
  296.  * Side effects:
  297.  *    Resources are freed.
  298.  *
  299.  *--------------------------------------------------------------
  300.  */
  301.  
  302. void
  303. Tk_Free3DBorder(border)
  304.     Tk_3DBorder border;        /* Token for border to be released. */
  305. {
  306.     register TkBorder *borderPtr = (TkBorder *) border;
  307.     Display *display = DisplayOfScreen(borderPtr->screen);
  308.  
  309.     borderPtr->refCount--;
  310.     if (borderPtr->refCount == 0) {
  311.     TkpFreeBorder(borderPtr);
  312.     if (borderPtr->bgColorPtr != NULL) {
  313.         Tk_FreeColor(borderPtr->bgColorPtr);
  314.     }
  315.     if (borderPtr->darkColorPtr != NULL) {
  316.         Tk_FreeColor(borderPtr->darkColorPtr);
  317.     }
  318.     if (borderPtr->lightColorPtr != NULL) {
  319.         Tk_FreeColor(borderPtr->lightColorPtr);
  320.     }
  321.     if (borderPtr->shadow != None) {
  322.         Tk_FreeBitmap(display, borderPtr->shadow);
  323.     }
  324.     if (borderPtr->bgGC != None) {
  325.         Tk_FreeGC(display, borderPtr->bgGC);
  326.     }
  327.     if (borderPtr->darkGC != None) {
  328.         Tk_FreeGC(display, borderPtr->darkGC);
  329.     }
  330.     if (borderPtr->lightGC != None) {
  331.         Tk_FreeGC(display, borderPtr->lightGC);
  332.     }
  333.     Tcl_DeleteHashEntry(borderPtr->hashPtr);
  334.     ckfree((char *) borderPtr);
  335.     }
  336. }
  337.  
  338. /*
  339.  *----------------------------------------------------------------------
  340.  *
  341.  * Tk_SetBackgroundFromBorder --
  342.  *
  343.  *    Change the background of a window to one appropriate for a given
  344.  *    3-D border.
  345.  *
  346.  * Results:
  347.  *    None.
  348.  *
  349.  * Side effects:
  350.  *    Tkwin's background gets modified.
  351.  *
  352.  *----------------------------------------------------------------------
  353.  */
  354.  
  355. void
  356. Tk_SetBackgroundFromBorder(tkwin, border)
  357.     Tk_Window tkwin;        /* Window whose background is to be set. */
  358.     Tk_3DBorder border;        /* Token for border. */
  359. {
  360.     register TkBorder *borderPtr = (TkBorder *) border;
  361.  
  362.     Tk_SetWindowBackground(tkwin, borderPtr->bgColorPtr->pixel);
  363. }
  364.  
  365. /*
  366.  *----------------------------------------------------------------------
  367.  *
  368.  * Tk_GetRelief --
  369.  *
  370.  *    Parse a relief description and return the corresponding
  371.  *    relief value, or an error.
  372.  *
  373.  * Results:
  374.  *    A standard Tcl return value.  If all goes well then
  375.  *    *reliefPtr is filled in with one of the values
  376.  *    TK_RELIEF_RAISED, TK_RELIEF_FLAT, or TK_RELIEF_SUNKEN.
  377.  *
  378.  * Side effects:
  379.  *    None.
  380.  *
  381.  *----------------------------------------------------------------------
  382.  */
  383.  
  384. int
  385. Tk_GetRelief(interp, name, reliefPtr)
  386.     Tcl_Interp *interp;        /* For error messages. */
  387.     char *name;            /* Name of a relief type. */
  388.     int *reliefPtr;        /* Where to store converted relief. */
  389. {
  390.     char c;
  391.     size_t length;
  392.  
  393.     c = name[0];
  394.     length = strlen(name);
  395.     if ((c == 'f') && (strncmp(name, "flat", length) == 0)) {
  396.     *reliefPtr = TK_RELIEF_FLAT;
  397.     } else if ((c == 'g') && (strncmp(name, "groove", length) == 0)
  398.         && (length >= 2)) {
  399.         *reliefPtr = TK_RELIEF_GROOVE;
  400.     } else if ((c == 'r') && (strncmp(name, "raised", length) == 0)
  401.         && (length >= 2)) {
  402.     *reliefPtr = TK_RELIEF_RAISED;
  403.     } else if ((c == 'r') && (strncmp(name, "ridge", length) == 0)) {
  404.         *reliefPtr = TK_RELIEF_RIDGE;
  405.     } else if ((c == 's') && (strncmp(name, "solid", length) == 0)) {
  406.     *reliefPtr = TK_RELIEF_SOLID;
  407.     } else if ((c == 's') && (strncmp(name, "sunken", length) == 0)) {
  408.     *reliefPtr = TK_RELIEF_SUNKEN;
  409.     } else {
  410.     sprintf(interp->result, "bad relief type \"%.50s\": must be %s",
  411.         name, "flat, groove, raised, ridge, solid, or sunken");
  412.     return TCL_ERROR;
  413.     }
  414.     return TCL_OK;
  415. }
  416.  
  417. /*
  418.  *--------------------------------------------------------------
  419.  *
  420.  * Tk_NameOfRelief --
  421.  *
  422.  *    Given a relief value, produce a string describing that
  423.  *    relief value.
  424.  *
  425.  * Results:
  426.  *    The return value is a static string that is equivalent
  427.  *    to relief.
  428.  *
  429.  * Side effects:
  430.  *    None.
  431.  *
  432.  *--------------------------------------------------------------
  433.  */
  434.  
  435. char *
  436. Tk_NameOfRelief(relief)
  437.     int relief;        /* One of TK_RELIEF_FLAT, TK_RELIEF_RAISED,
  438.              * or TK_RELIEF_SUNKEN. */
  439. {
  440.     if (relief == TK_RELIEF_FLAT) {
  441.     return "flat";
  442.     } else if (relief == TK_RELIEF_SUNKEN) {
  443.     return "sunken";
  444.     } else if (relief == TK_RELIEF_RAISED) {
  445.     return "raised";
  446.     } else if (relief == TK_RELIEF_GROOVE) {
  447.     return "groove";
  448.     } else if (relief == TK_RELIEF_RIDGE) {
  449.     return "ridge";
  450.     } else if (relief == TK_RELIEF_SOLID) {
  451.     return "solid";
  452.     } else {
  453.     return "unknown relief";
  454.     }
  455. }
  456.  
  457. /*
  458.  *--------------------------------------------------------------
  459.  *
  460.  * Tk_Draw3DPolygon --
  461.  *
  462.  *    Draw a border with 3-D appearance around the edge of a
  463.  *    given polygon.
  464.  *
  465.  * Results:
  466.  *    None.
  467.  *
  468.  * Side effects:
  469.  *    Information is drawn in "drawable" in the form of a
  470.  *    3-D border borderWidth units width wide on the left
  471.  *    of the trajectory given by pointPtr and numPoints (or
  472.  *    -borderWidth units wide on the right side, if borderWidth
  473.  *    is negative).
  474.  *
  475.  *--------------------------------------------------------------
  476.  */
  477.  
  478. void
  479. Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  480.     borderWidth, leftRelief)
  481.     Tk_Window tkwin;        /* Window for which border was allocated. */
  482.     Drawable drawable;        /* X window or pixmap in which to draw. */
  483.     Tk_3DBorder border;        /* Token for border to draw. */
  484.     XPoint *pointPtr;        /* Array of points describing
  485.                  * polygon.  All points must be
  486.                  * absolute (CoordModeOrigin). */
  487.     int numPoints;        /* Number of points at *pointPtr. */
  488.     int borderWidth;        /* Width of border, measured in
  489.                  * pixels to the left of the polygon's
  490.                  * trajectory.   May be negative. */
  491.     int leftRelief;        /* TK_RELIEF_RAISED or
  492.                  * TK_RELIEF_SUNKEN: indicates how
  493.                  * stuff to left of trajectory looks
  494.                  * relative to stuff on right. */
  495. {
  496.     XPoint poly[4], b1, b2, newB1, newB2;
  497.     XPoint perp, c, shift1, shift2;    /* Used for handling parallel lines. */
  498.     register XPoint *p1Ptr, *p2Ptr;
  499.     TkBorder *borderPtr = (TkBorder *) border;
  500.     GC gc;
  501.     int i, lightOnLeft, dx, dy, parallel, pointsSeen;
  502.     Display *display = Tk_Display(tkwin);
  503.  
  504.     if (borderPtr->lightGC == None) {
  505.     TkpGetShadows(borderPtr, tkwin);
  506.     }
  507.  
  508.     /*
  509.      * Handle grooves and ridges with recursive calls.
  510.      */
  511.  
  512.     if ((leftRelief == TK_RELIEF_GROOVE) || (leftRelief == TK_RELIEF_RIDGE)) {
  513.     int halfWidth;
  514.  
  515.     halfWidth = borderWidth/2;
  516.     Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  517.         halfWidth, (leftRelief == TK_RELIEF_GROOVE) ? TK_RELIEF_RAISED
  518.         : TK_RELIEF_SUNKEN);
  519.     Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  520.         -halfWidth, (leftRelief == TK_RELIEF_GROOVE) ? TK_RELIEF_SUNKEN
  521.         : TK_RELIEF_RAISED);
  522.     return;
  523.     }
  524.  
  525.     /*
  526.      * If the polygon is already closed, drop the last point from it
  527.      * (we'll close it automatically).
  528.      */
  529.  
  530.     p1Ptr = &pointPtr[numPoints-1];
  531.     p2Ptr = &pointPtr[0];
  532.     if ((p1Ptr->x == p2Ptr->x) && (p1Ptr->y == p2Ptr->y)) {
  533.     numPoints--;
  534.     }
  535.  
  536.     /*
  537.      * The loop below is executed once for each vertex in the polgon.
  538.      * At the beginning of each iteration things look like this:
  539.      *
  540.      *          poly[1]       /
  541.      *             *        /
  542.      *             |      /
  543.      *             b1   * poly[0] (pointPtr[i-1])
  544.      *             |    |
  545.      *             |    |
  546.      *             |    |
  547.      *             |    |
  548.      *             |    |
  549.      *             |    | *p1Ptr            *p2Ptr
  550.      *             b2   *--------------------*
  551.      *             |
  552.      *             |
  553.      *             x-------------------------
  554.      *
  555.      * The job of this iteration is to do the following:
  556.      * (a) Compute x (the border corner corresponding to
  557.      *     pointPtr[i]) and put it in poly[2].  As part of
  558.      *       this, compute a new b1 and b2 value for the next
  559.      *       side of the polygon.
  560.      * (b) Put pointPtr[i] into poly[3].
  561.      * (c) Draw the polygon given by poly[0..3].
  562.      * (d) Advance poly[0], poly[1], b1, and b2 for the
  563.      *     next side of the polygon.
  564.      */
  565.  
  566.     /*
  567.      * The above situation doesn't first come into existence until
  568.      * two points have been processed;  the first two points are
  569.      * used to "prime the pump", so some parts of the processing
  570.      * are ommitted for these points.  The variable "pointsSeen"
  571.      * keeps track of the priming process;  it has to be separate
  572.      * from i in order to be able to ignore duplicate points in the
  573.      * polygon.
  574.      */
  575.  
  576.     pointsSeen = 0;
  577.     for (i = -2, p1Ptr = &pointPtr[numPoints-2], p2Ptr = p1Ptr+1;
  578.         i < numPoints; i++, p1Ptr = p2Ptr, p2Ptr++) {
  579.     if ((i == -1) || (i == numPoints-1)) {
  580.         p2Ptr = pointPtr;
  581.     }
  582.     if ((p2Ptr->x == p1Ptr->x) && (p2Ptr->y == p1Ptr->y)) {
  583.         /*
  584.          * Ignore duplicate points (they'd cause core dumps in
  585.          * ShiftLine calls below).
  586.          */
  587.         continue;
  588.     }
  589.     ShiftLine(p1Ptr, p2Ptr, borderWidth, &newB1);
  590.     newB2.x = newB1.x + (p2Ptr->x - p1Ptr->x);
  591.     newB2.y = newB1.y + (p2Ptr->y - p1Ptr->y);
  592.     poly[3] = *p1Ptr;
  593.     parallel = 0;
  594.     if (pointsSeen >= 1) {
  595.         parallel = Intersect(&newB1, &newB2, &b1, &b2, &poly[2]);
  596.  
  597.         /*
  598.          * If two consecutive segments of the polygon are parallel,
  599.          * then things get more complex.  Consider the following
  600.          * diagram:
  601.          *
  602.          * poly[1]
  603.          *    *----b1-----------b2------a
  604.          *                                \
  605.          *                                  \
  606.          *         *---------*----------*    b
  607.          *        poly[0]  *p2Ptr   *p1Ptr  /
  608.          *                                /
  609.          *              --*--------*----c
  610.          *              newB1    newB2
  611.          *
  612.          * Instead of using x and *p1Ptr for poly[2] and poly[3], as
  613.          * in the original diagram, use a and b as above.  Then instead
  614.          * of using x and *p1Ptr for the new poly[0] and poly[1], use
  615.          * b and c as above.
  616.          *
  617.          * Do the computation in three stages:
  618.          * 1. Compute a point "perp" such that the line p1Ptr-perp
  619.          *    is perpendicular to p1Ptr-p2Ptr.
  620.          * 2. Compute the points a and c by intersecting the lines
  621.          *    b1-b2 and newB1-newB2 with p1Ptr-perp.
  622.          * 3. Compute b by shifting p1Ptr-perp to the right and
  623.          *    intersecting it with p1Ptr-p2Ptr.
  624.          */
  625.  
  626.         if (parallel) {
  627.         perp.x = p1Ptr->x + (p2Ptr->y - p1Ptr->y);
  628.         perp.y = p1Ptr->y - (p2Ptr->x - p1Ptr->x);
  629.         (void) Intersect(p1Ptr, &perp, &b1, &b2, &poly[2]);
  630.         (void) Intersect(p1Ptr, &perp, &newB1, &newB2, &c);
  631.         ShiftLine(p1Ptr, &perp, borderWidth, &shift1);
  632.         shift2.x = shift1.x + (perp.x - p1Ptr->x);
  633.         shift2.y = shift1.y + (perp.y - p1Ptr->y);
  634.         (void) Intersect(p1Ptr, p2Ptr, &shift1, &shift2, &poly[3]);
  635.         }
  636.     }
  637.     if (pointsSeen >= 2) {
  638.         dx = poly[3].x - poly[0].x;
  639.         dy = poly[3].y - poly[0].y;
  640.         if (dx > 0) {
  641.         lightOnLeft = (dy <= dx);
  642.         } else {
  643.         lightOnLeft = (dy < dx);
  644.         }
  645.         if (lightOnLeft ^ (leftRelief == TK_RELIEF_RAISED)) {
  646.         gc = borderPtr->lightGC;
  647.         } else {
  648.         gc = borderPtr->darkGC;
  649.         }
  650.         XFillPolygon(display, drawable, gc, poly, 4, Convex,
  651.             CoordModeOrigin);
  652.     }
  653.     b1.x = newB1.x;
  654.     b1.y = newB1.y;
  655.     b2.x = newB2.x;
  656.     b2.y = newB2.y;
  657.     poly[0].x = poly[3].x;
  658.     poly[0].y = poly[3].y;
  659.     if (parallel) {
  660.         poly[1].x = c.x;
  661.         poly[1].y = c.y;
  662.     } else if (pointsSeen >= 1) {
  663.         poly[1].x = poly[2].x;
  664.         poly[1].y = poly[2].y;
  665.     }
  666.     pointsSeen++;
  667.     }
  668. }
  669.  
  670. /*
  671.  *----------------------------------------------------------------------
  672.  *
  673.  * Tk_Fill3DRectangle --
  674.  *
  675.  *    Fill a rectangular area, supplying a 3D border if desired.
  676.  *
  677.  * Results:
  678.  *    None.
  679.  *
  680.  * Side effects:
  681.  *    Information gets drawn on the screen.
  682.  *
  683.  *----------------------------------------------------------------------
  684.  */
  685.  
  686. void
  687. Tk_Fill3DRectangle(tkwin, drawable, border, x, y, width,
  688.     height, borderWidth, relief)
  689.     Tk_Window tkwin;        /* Window for which border was allocated. */
  690.     Drawable drawable;        /* X window or pixmap in which to draw. */
  691.     Tk_3DBorder border;        /* Token for border to draw. */
  692.     int x, y, width, height;    /* Outside area of rectangular region. */
  693.     int borderWidth;        /* Desired width for border, in
  694.                  * pixels. Border will be *inside* region. */
  695.     int relief;            /* Indicates 3D effect: TK_RELIEF_FLAT,
  696.                  * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */
  697. {
  698.     register TkBorder *borderPtr = (TkBorder *) border;
  699.     int doubleBorder;
  700.  
  701.     /*
  702.      * This code is slightly tricky because it only draws the background
  703.      * in areas not covered by the 3D border. This avoids flashing
  704.      * effects on the screen for the border region.
  705.      */
  706.   
  707.     if (relief == TK_RELIEF_FLAT) {
  708.     borderWidth = 0;
  709.     }
  710.     doubleBorder = 2*borderWidth;
  711.  
  712.     if ((width > doubleBorder) && (height > doubleBorder)) {
  713.     XFillRectangle(Tk_Display(tkwin), drawable, borderPtr->bgGC,
  714.         x + borderWidth, y + borderWidth,
  715.         (unsigned int) (width - doubleBorder),
  716.         (unsigned int) (height - doubleBorder));
  717.     }
  718.     if (borderWidth) {
  719.     Tk_Draw3DRectangle(tkwin, drawable, border, x, y, width,
  720.         height, borderWidth, relief);
  721.     }
  722. }
  723.  
  724. /*
  725.  *----------------------------------------------------------------------
  726.  *
  727.  * Tk_Fill3DPolygon --
  728.  *
  729.  *    Fill a polygonal area, supplying a 3D border if desired.
  730.  *
  731.  * Results:
  732.  *    None.
  733.  *
  734.  * Side effects:
  735.  *    Information gets drawn on the screen.
  736.  *
  737.  *----------------------------------------------------------------------
  738.  */
  739.  
  740. void
  741. Tk_Fill3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  742.     borderWidth, leftRelief)
  743.     Tk_Window tkwin;        /* Window for which border was allocated. */
  744.     Drawable drawable;        /* X window or pixmap in which to draw. */
  745.     Tk_3DBorder border;        /* Token for border to draw. */
  746.     XPoint *pointPtr;        /* Array of points describing
  747.                  * polygon.  All points must be
  748.                  * absolute (CoordModeOrigin). */
  749.     int numPoints;        /* Number of points at *pointPtr. */
  750.     int borderWidth;        /* Width of border, measured in
  751.                  * pixels to the left of the polygon's
  752.                  * trajectory.   May be negative. */
  753.     int leftRelief;            /* Indicates 3D effect of left side of
  754.                  * trajectory relative to right:
  755.                  * TK_RELIEF_FLAT, TK_RELIEF_RAISED,
  756.                  * or TK_RELIEF_SUNKEN. */
  757. {
  758.     register TkBorder *borderPtr = (TkBorder *) border;
  759.  
  760.     XFillPolygon(Tk_Display(tkwin), drawable, borderPtr->bgGC,
  761.         pointPtr, numPoints, Complex, CoordModeOrigin);
  762.     if (leftRelief != TK_RELIEF_FLAT) {
  763.     Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  764.         borderWidth, leftRelief);
  765.     }
  766. }
  767.  
  768. /*
  769.  *--------------------------------------------------------------
  770.  *
  771.  * BorderInit --
  772.  *
  773.  *    Initialize the structures used for border management.
  774.  *
  775.  * Results:
  776.  *    None.
  777.  *
  778.  * Side effects:
  779.  *    Read the code.
  780.  *
  781.  *------------------------------------------------------q/2)/q;
  782.     }
  783.     return 0;
  784. }
  785.